#include <algorithm/analytical_model/algorithm/cpu/GeometryUtils.h>
#include <algorithm/analytical_model/algorithm/cpu/VectorConvert.h>
#include <algorithm/analytical_model/algorithm/cpu/heliostat/RectangleHeliostat.h>
#include <algorithm/shared/utils/Vec3.h>

#include <array>

using namespace solar::cuda::inter_op;

#define VEC3_COPY(name) Vec3 name##_vec = toVec3(name);

auto solar::cpu::setNormal(const Float3& pos, const Float3& focus_center, const Float3& sunray_dir) -> Float3
{
    auto local_center = toVec3(pos);
    VEC3_COPY(focus_center)
    VEC3_COPY(sunray_dir)
    auto reflect_dir = (focus_center_vec - local_center).get_unit_vector();
    return toFloat3((reflect_dir - sunray_dir_vec).get_unit_vector());
}

auto solar::cpu::getImagePlaneAxis(const Float3& focus_center, const Float3& pos,
                                   const Float3* vertices) -> std::tuple<Float3, Float3, Float3>
{
    Vec3 x_axis;
    Vec3 y_axis;
    Vec3 z_axis;
    VEC3_COPY(focus_center)
    VEC3_COPY(pos)
    auto reflect_dir = focus_center_vec - pos_vec;
    z_axis = -reflect_dir.get_unit_vector();
    auto z_axis_copy = toFloat3(z_axis);
    auto reflect_dir_copy = toFloat3(reflect_dir);
    std::array<Float3, 4> interv{};
    for (int i = 0; i < 4; i++)
    {
        std::tie(interv[i], std::ignore) =
            intersect(z_axis_copy, focus_center, vertices[i], reflect_dir_copy);
    }
    x_axis = (toVec3(interv[2]) - toVec3(interv[1])).get_unit_vector();
    y_axis = solar::cross(z_axis, x_axis);
    return {toFloat3(x_axis), toFloat3(y_axis), toFloat3(z_axis)};
}
